package com.iwhalecloud.citybrain.flow.platform.manager.application.listener;


import java.util.Date;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Objects;

import com.iwhalecloud.citybrain.flow.platform.manager.application.utils.MessageFillUtils;
import com.iwhalecloud.citybrain.flow.platform.manager.domain.enums.NoticeTypeEnum;
import com.iwhalecloud.citybrain.flow.platform.manager.domain.model.FlowMessageVo;
import com.iwhalecloud.citybrain.flow.platform.manager.domain.model.FlowProcessInstanceTraceVo;
import com.iwhalecloud.citybrain.flow.platform.manager.domain.model.notice.FlowReNoticeInfo;
import com.iwhalecloud.citybrain.flow.platform.manager.domain.repository.*;
import org.apache.commons.lang3.StringUtils;
import org.flowable.engine.TaskService;
import org.flowable.task.service.impl.persistence.entity.TaskEntityImpl;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.connection.Message;
import org.springframework.data.redis.connection.MessageListener;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;


@Component
public class RedisMessageListener implements MessageListener {

    private final Logger logger = LoggerFactory.getLogger(RedisMessageListener.class);

    @Autowired
    private FlowRuTimeoutSettingRepository flowRuTimeoutSettingRepository;

    @Autowired
    private FlowProcessInstanceTraceRepository flowProcessInstanceTraceRepository;

    @Autowired
    private FlowTaskTraceRepository flowTaskTraceRepository;

    @Autowired
    private FlowMessageRepository flowMessageRepository;

    @Autowired
    private RedisTemplate<String, String> redisTemplate;

    @Autowired
    private TaskService taskService;

    @Autowired
    private FlowNoticeTemplateRepository flowNoticeTemplateRepository;





    @Override
    public void onMessage(Message message, byte[] pattern) {
        //获取将要通知消息的key
        String key = (String) redisTemplate.getValueSerializer().deserialize(message.getBody());
        if (key.contains("::")){
            String id = key.split("::")[0];
            FlowReNoticeInfo flowReNoticeInfo = flowRuTimeoutSettingRepository.getNeedNotifyTimeoutAndWarningNoticeById(Long.parseLong(id));
            if (Objects.nonNull(flowReNoticeInfo)){
                logger.info("发送通知：" + flowReNoticeInfo);
                List<FlowReNoticeInfo> candidateItemsToUpdateStatus = new LinkedList<>();
                FlowMessageVo entity = new FlowMessageVo();
                entity.setMsgType(flowReNoticeInfo.getType());
                entity.setProcessInstanceId(flowReNoticeInfo.getProcInstId());
                entity.setTaskId(flowReNoticeInfo.getTaskId());
                entity.setStatus(0);
                entity.setReceiverCode(flowReNoticeInfo.getStaCode());
                entity.setReceiverName(flowReNoticeInfo.getCreateBy());
                entity.setSenderCode(flowReNoticeInfo.getStaCode());
                entity.setSenderName(flowReNoticeInfo.getCreateBy());
                entity.setCreateTime(new Date());
                FlowProcessInstanceTraceVo processInstanceTraceByProcessInstanceId = flowProcessInstanceTraceRepository.getProcessInstanceTraceByProcessInstanceId(flowReNoticeInfo.getProcInstId());
                if (Objects.nonNull(processInstanceTraceByProcessInstanceId)) {
                    entity.setProcessName(processInstanceTraceByProcessInstanceId.getModelName());
                }
                Map<String,Object> map=new HashMap<>();
                String taskName="";
                String currentHandler = "";
                String processName = Objects.nonNull(processInstanceTraceByProcessInstanceId) ? processInstanceTraceByProcessInstanceId.getModelName() : null;
                String originator = flowReNoticeInfo.getCreateBy();
                if (StringUtils.isNotBlank(flowReNoticeInfo.getTaskId())){
                    TaskEntityImpl currTask = (TaskEntityImpl) taskService.createTaskQuery().taskId(flowReNoticeInfo.getTaskId()).singleResult();
                    if (Objects.nonNull(currTask)) {
                        taskName=currTask.getName();
                        currentHandler=currTask.getAssignee();
                    }
                }
                map.put("processName",processName);
                map.put("taskName",taskName);
                map.put("originator",originator);
                map.put("currentHandler",currentHandler);
                entity.setMsgBoby(MessageFillUtils.replaceWithMap(flowReNoticeInfo.getContent(),map));
                entity.setMsgTitle(MessageFillUtils.replaceWithMap(flowReNoticeInfo.getTitle(),map));
                flowMessageRepository.insertMessage(entity);
                flowNoticeTemplateRepository.updateSendStatus(flowReNoticeInfo.getRuNoticeChannelId());
                candidateItemsToUpdateStatus.add(flowReNoticeInfo);
                updateProcessInstanceOrTaskStatusAfterSendNotice(candidateItemsToUpdateStatus);
            }
        }
    }


    private void updateProcessInstanceOrTaskStatusAfterSendNotice(List<FlowReNoticeInfo> candidateItemsToUpdateStatus) {

        for (FlowReNoticeInfo item : candidateItemsToUpdateStatus) {
            if (Objects.equals(NoticeTypeEnum.PROCESS_TIMEOUT_NOTICE.getCode(), item.getType())||
                    Objects.equals(NoticeTypeEnum.TASK_TIMEOUT_NOTICE.getCode(), item.getType())) {

                //超时通知
                if (isProcessInstanceNotice(item)) {
                    flowProcessInstanceTraceRepository.updateStatusToTimeout(item.getProcInstId());
                } else {
                    flowTaskTraceRepository.updateStatusToTimeout(item.getTaskId());
                }
            } else {

                //预警通知
                if (isProcessInstanceNotice(item)) {
                    flowProcessInstanceTraceRepository.updateStatusToWarning(item.getProcInstId());
                } else {
                    flowTaskTraceRepository.updateStatusToWarning(item.getTaskId());
                }
            }

        }
    }

    private boolean isProcessInstanceNotice(FlowReNoticeInfo item) {
        return StringUtils.isNotBlank(item.getProcInstId()) && StringUtils.isBlank(item.getTaskId());
    }

}
